home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD Exchange
/
CD Exchange - Volume 1.iso
/
d.t.p
/
utils
/
others
/
pcal
/
pcalutil.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-21
|
21KB
|
981 lines
/*
* pcalutil.c - utility routines for Pcal
*
* Contents:
*
* alloc
* calc_day
* calc_weekday
* calc_year_day
* ci_strcmp
* ci_strncmp
* copy_text
* cvt_escape
* find_executable
* getline
* is_valid
* loadwords
* mk_filespec
* mk_path
* normalize
* note_box
* note_day
* split_date
* trnlog
*
* Revision history:
*
* 4.3 AWR 11/22/91 added special case to loadwords():
* split -<flag>"<text>" into two words
*
* removed octal/hex escape functionality
* from getline() to new routine
* cvt_escape() (for use elsewhere)
*
* 10/25/91 added parameters to loadwords() and
* getline() to avoid always using same
* global data
*
* 10/15/91 revised UN*X mk_filespec() to translate
* "~/" in path name as well as file name
*
* 4.2 AWR 10/08/91 support -[kK] flags (cf. note_box())
*
* 10/03/91 added note_box(), note_day()
*
* 4.11 AWR 08/20/91 documented find_executable()
*
* 4.02 AWR 06/07/91 added find_executable()
*
* 4.0 AWR 02/24/91 Revised getline() and copy_text() to
* handle C-style escapes of characters
* and octal/hex numbers
*
* AWR 02/19/91 Added support for negative ordinals
* in calc_day(), calc_year_day()
*
* AWR 02/04/91 Added calc_year_day()
*
* AWR 01/15/91 Extracted from pcal.c
*
*/
/*
* Standard headers:
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
/*
* Pcal-specific definitions:
*/
#include "pcaldefs.h"
#include "pcalglob.h"
#include "pcallang.h"
/*
* Macros:
*/
/* skip over numeric field and subsequent non-numeric characters */
#define SKIP_FIELD(p) \
do { while (*p && isdigit(*p)) p++; \
while (*p && !isdigit(*p)) p++; } while (0)
/* guarantee that a path is terminated by the END_PATH character */
#define TERM_PATH(path) \
do { char *p; \
if ((p = P_LASTCHAR(path)) && *p != END_PATH) \
*++p = END_PATH, *++p = '\0'; } while (0)
/*
* General-purpose utility routines
*/
/*
* alloc - interface to calloc(); terminates if unsuccessful
*/
#ifdef PROTOS
char *alloc(int size)
#else
char *alloc(size)
int size;
#endif
{
char *p;
if (size == 0) /* not all calloc()s like null requests */
size = 1;
if ((p = calloc(1, size)) == NULL) {
FPR(stderr, E_ALLOC_ERR, progname);
exit(EXIT_FAILURE);
}
return p;
}
/*
* ci_str{n}cmp - case-insensitive flavors of strcmp(), strncmp()
*/
#ifdef PROTOS
int ci_strcmp(register char *s1,
register char *s2)
#else
int ci_strcmp(s1, s2)
register char *s1, *s2;
#endif
{
register char c1, c2;
for ( ; (c1 = TOLOWER(*s1)) == (c2 = TOLOWER(*s2)); s1++, s2++)
if (c1 == '\0')
return 0;
return c1 - c2;
}
#ifdef PROTOS
int ci_strncmp(register char *s1,
register char *s2,
int n)
#else
int ci_strncmp(s1, s2, n)
register char *s1, *s2;
int n;
#endif
{
register char c1, c2;
for ( ; --n >= 0 && (c1 = TOLOWER(*s1)) == (c2 = TOLOWER(*s2)); s1++, s2++)
if (c1 == '\0')
return 0;
return n < 0 ? 0 : c1 - c2;
}
/*
* Date calculation routines (see also macros in pcaldefs.h)
*/
/*
* normalize - adjust day in case it has crossed month (or year) bounds
*/
#ifdef PROTOS
void normalize(DATE *pd)
#else
void normalize(pd)
DATE *pd; /* pointer to date */
#endif
{
int len;
/* adjust if day is in previous or following month */
while (pd->dd < 1) {
pd->yy = PREV_YEAR(pd->mm, pd->yy);
pd->mm = PREV_MONTH(pd->mm, pd->yy);
pd->dd += LENGTH_OF(pd->mm, pd->yy);
}
while (pd->dd > (len = LENGTH_OF(pd->mm, pd->yy))) {
pd->dd -= len;
pd->yy = NEXT_YEAR(pd->mm, pd->yy);
pd->mm = NEXT_MONTH(pd->mm, pd->yy);
}
}
/*
* calc_day - calculate calendar date from ordinal date (e.g., "first Friday
* in November", "last day in October"); return calendar date if it exists,
* 0 if it does not
*/
#ifdef PROTOS
int calc_day(int ord,
int wkd,
int mm)
#else
int calc_day(ord, wkd, mm)
int ord;
int wkd;
int mm;
#endif
{
#ifdef PROTOS
int first, last, day, (*pfcn)(int, int, int);
#else
int first, last, day, (*pfcn)();
#endif
if (IS_WILD(wkd)) { /* "day", "weekday", "workday", or "holiday" */
pfcn = pdatefcn[wkd - WILD_FIRST];
last = LENGTH_OF(mm, curr_year);
if (ord < 0) { /* search backwards */
for (day = last;
day >= 1 &&
!((*pfcn)(mm, day, curr_year) && ++ord == 0);
day--)
;
} else { /* search forwards */
for (day = 1;
day <= last &&
!((*pfcn)(mm, day, curr_year) && --ord == 0);
day++)
;
}
return is_valid(mm, day, curr_year) ? day : 0;
} else { /* fixed weekday - calculate it */
first = (wkd - FIRST_OF(mm, curr_year) + 7) % 7 + 1;
if (ord < 0) { /* get last (try 5th, then 4th) */
if (!is_valid(mm, last = first + 28, curr_year))
last -= 7;
if (!is_valid(mm, day = last + 7 * (ord + 1),
curr_year))
day = 0;
}
else
if (!is_valid(mm, day = first + 7 * (ord - 1),
curr_year))
day = 0;
return day;
}
}
/*
* calc_year_day - calculate calendar date from ordinal date within year
* (e.g., "last Friday in year", "10th holiday in year"); if date exists,
* fill in pdate and return TRUE; else return FALSE
*/
#ifdef PROTOS
int calc_year_day(int ord,
int wkd,
DATE *pdate)
#else
int calc_year_day(ord, wkd, pdate)
int ord;
int wkd;
DATE *pdate;
#endif
{
#ifdef PROTOS
int incr, (*pfcn)(int, int, int);
#else
int incr, (*pfcn)();
#endif
DATE date;
if (IS_WILD(wkd)) { /* "day", "weekday", "workday", or "holiday" */
pfcn = pdatefcn[wkd - WILD_FIRST];
if (ord < 0) { /* nth occurrence backwards */
MAKE_DATE(date, DEC, 31, curr_year);
ord = -ord;
incr = -1;
} else { /* nth occurrence forwards */
MAKE_DATE(date, JAN, 1, curr_year);
incr = 1;
}
/* search for selected occurrence of specified wildcard */
while (date.yy == curr_year &&
!((*pfcn)(date.mm, date.dd, date.yy) && --ord == 0)) {
date.dd += incr;
normalize(&date);
}
} else { /* fixed weekday - calculate it */
if (ord < 0)
MAKE_DATE(date, DEC,
calc_day(-1, wkd, DEC) + 7 * (ord + 1),
curr_year);
else
MAKE_DATE(date, JAN,
calc_day(1, wkd, JAN) + 7 * (ord - 1),
curr_year);
normalize(&date);
}
return date.yy == curr_year ? (*pdate = date, TRUE) : FALSE;
}
/*
* calc_weekday - return the weekday (0-6) of mm/dd/yy (mm: 1-12)
*/
#ifdef PROTOS
int calc_weekday(int mm,
int dd,
int yy)
#else
int calc_weekday(mm, dd, yy)
int mm;
int dd;
int yy;
#endif
{
return (yy + (yy-1)/4 - (yy-1)/100 + (yy-1)/400 + OFFSET_OF(mm, yy) +
(dd-1)) % 7;
}
/*
* note_day - translate n (from "note/<n>" spec) to appropriate note text
* day for mm/yy; return note text day if in range, 0 if not
*/
#ifdef PROTOS
int note_day(int mm,
int n,
int yy)
#else
int note_day(mm, n, yy)
int mm;
int n;
int yy;
#endif
{
int day, lastday;
if (n == 0) /* convert 0 to appropriate default */
n = NOTE_DEFAULT;
/* lastday depends on month length and presence (but not position) of
* small calendars
*/
lastday = LAST_NOTE_DAY - (LENGTH_OF(mm, yy) - 28) -
(small_cal_pos == SC_NONE ? 0 : 2);
/* count forward if n is positive, backward if negative */
day = (n > 0) ? FIRST_NOTE_DAY + n - 1 : lastday + n + 1;
/* make sure result is valid for this month/year */
return (day >= FIRST_NOTE_DAY && day <= lastday) ? day : 0;
}
/*
* note_box - translate dd from note text day to box number for mm/yy,
* adjusting for presence and position of small calendars
*/
#ifdef PROTOS
int note_box(int mm,
int dd,
int yy)
#else
int note_box(mm, dd, yy)
int mm;
int dd;
int yy;
#endif
{
int startbox = START_BOX(mm, yy), pc, nc;
/* move starting box to second row if conflict with small calendars */
if ((pc = prev_cal_box[small_cal_pos]) == startbox ||
(nc = next_cal_box[small_cal_pos]) == startbox)
startbox += 7;
dd -= FIRST_NOTE_DAY; /* convert to note box number 0..13 */
dd += (pc == 0) + (nc == 1); /* adjust for small calendars in 0, 1 */
/* position box after calendar body if no room before */
return dd < startbox ? dd : dd + LENGTH_OF(mm, yy);
}
/*
* is_valid - return TRUE if m/d/y is a valid